<?php


namespace app\common\cachemodel;


use app\common\lib\astrolog\FortunesChange;
use app\common\model\BaseCache;
use Exception;
use think\Log;
use XznsTools\cache\CacheManage;

/**
 * 年运模型
 * Class YearFortune
 * @package app\common\cachemodel
 */
class YearFortune extends BaseCache
{
    protected $table = 'wechat_backup_07_18_14_43_00.app_year_fortune';
    protected $cacheModel = 'fortune.fortune_year';

    /**
     * 获取年运
     * @param array $map
     * @return array|bool|mixed
     * @throws Exception
     */
    public function getYearFortune($map = [])
    {
        if (empty($map) || !isset($map['rid']) || !isset($map['year']))
        {
            return [];
        }
        $idKey = $map['rid'] . ':' . $map['year'];

        $data = CacheManage::getInstance()->setCacheConfig($this->cacheModel, $idKey)->getDataAndSet(function () use ($map)
        {
            return $this->getFortuneYearByDb($map['rid'], $map['year']);
        });

        $data['scores'] = json_decode($data['scores'], true);
        $data['point'] = json_decode($data['point'], true);

        return $data;
    }

    /**
     * 获取运势信息
     * @param $rid
     * @param $year
     * @return mixed|string
     */
    public function getFortuneYearByDb($rid, $year)
    {
        try
        {
            $data = $this->field('fortune scores,topic,point')->where(['rid' => $rid, 'year' => $year])->findOrFail()->toArray();
        }
        catch (Exception $e)
        {
            $data = '';
        }

        return $data;
    }

    /**
     * 获取年运缓存
     * @param array $map
     * @return array
     * @throws Exception
     */
    public function getDatas($map = [])
    {
        $result = [
            'scores' => [],
            'topics' => [],
            'topic' => -1,
            'point' => [],
        ];

        if (empty($map))
        {
            return $result;
        }
        $years = $this->getYearFortune($map);
        $result['scores'] = $years['scores'];
        $result['topic'] = $years['topic'];
        $result['point'] = $years['point'];

        $monthFortuneModel = new MonthFortune();
        for ($i = 1; $i < 13; $i++)
        {
            $month = $i < 10 ? '0' . $i : $i;
            $start_time = $map['year'] . '-' . $month;

            $topic = $monthFortuneModel->getMonthFortune(['rid' => $map['rid'], 'month' => $start_time]);
            if ($topic)
            {
                $result['topics'] += json_decode($topic, true);
            } else
            {
                Log::write('年度运势-月份数据缺失，请重新计算：' . $start_time . ' rid=' . $map['rid'], 'error', true);
            }
        }

        return $result;
    }

    /**
     * 获取订单备份档案信息
     * @param string $order_id
     * @return array|bool|mixed|string
     * @throws Exception
     */
    public function getOrderRecodeBackRecode($order_id)
    {
        return CacheManage::getInstance()->setCacheConfig('fortune.back_recode')->setCacheKeyDetail('details2', $order_id)->getDataAndSet(function () use ($order_id)
        {
            try
            {
                return $this->alias('y')
                    ->join('wechat_backup_07_18_14_43_00.app_fortune_recode_back r', 'y.rid_back=r.id')
                    ->where(['y.order_id' => $order_id, 'y.type' => 1])
                    ->column('r.recode_info', 'r.id');
            }
            catch (\Exception $e)
            {
                return [];
            }
        }, [], 'details2');
    }

    /**
     * 获取档案年运解锁年份 v2.6.0
     * @param int $rid
     * @return array
     * @throws Exception
     */
    public function getReocdeFortuneUnlockYears(int $rid): array
    {
        $unlockMonth = CacheManage::getInstance()
            ->setCacheConfig($this->cacheModel)
            ->setCacheKeyDetail('list_v2', $rid)
            ->setPage(-1)
            ->getListPageDataIds(function ($isCache = true, $sortType = 'desc') use ($rid)
            {
                try
                {
                    $fortuneMonth = $this->where('rid', $rid)->where('status', '>', 0)->order('id asc')->column('id', 'year');
                    $resData = [];
                    foreach ($fortuneMonth as $year => $id)
                    {
                        $resData[$year] = [
                            'id' => $id,
                            'year' => $year,
                        ];
                    }

                    return $resData;
                }
                catch (Exception $e)
                {
                    return [];
                }
            }, 'id', 0, 'list_v2');

        return array_keys($unlockMonth['data']);
    }

    /**
     * 批量获取 档案解锁年运详情 v2.6.0
     * @param int $rid
     * @param array $years
     * @param array $field
     * @return array
     * @throws Exception
     */
    public function batchGetRecodeFortuneYearInfo(int $rid, array $years, array $field = []): array
    {
        $cacheKeys = [];
        foreach ($years as $yearItem)
        {
            $cacheKeys[] = $rid . ':' . $yearItem;
        }

        if (empty($cacheKeys))
        {
            return [];
        }

        $resData = CacheManage::getInstance()->setCacheConfig($this->cacheModel)->setCacheType('hash')
            ->batchGetCache($cacheKeys, function ($ids)
            {
                try
                {
                    $rid = 0;
                    $years = [];
                    foreach ($ids as $cacheKeyItem)
                    {
                        [$rid, $year] = explode(':', $cacheKeyItem);
                        $years[] = $year;
                    }

                    $fortuneData = $this->where('rid', (int)$rid)->whereIn('year', $years)->where('status', '>', 0)->order('id asc')->column('*', 'id');

                    if (empty($fortuneData))
                    {
                        return [];
                    }
                    $backrids = array_unique(array_column($fortuneData, 'rid_back'));

                    $backRecode = $this->table('wechat_backup_07_18_14_43_00.app_fortune_recode_back')->whereIn('id', $backrids)->column('recode_info', 'id');
                    foreach ($backRecode as $backRid => $reocdeInfo)
                    {
                        $backRecode[$backRid] = \GuzzleHttp\json_decode($reocdeInfo, true);
                    }

                    $resFortuneData = [];
                    foreach ($fortuneData as $fortuneDatum)
                    {
                        // 若数据异常，直接跳过
                        if ($fortuneDatum['order_id'] === '' || !$fortuneDatum['rid_back'])
                        {
                            continue;
                        }
                        $fortuneInfo = [
                            'id' => $fortuneDatum['id'],
                            'type' => $fortuneDatum['type'],
                            'order_id' => $fortuneDatum['order_id'],
                            'rid_back' => $fortuneDatum['rid_back'],
                            'status' => $fortuneDatum['status'],
                            'rid' => $fortuneDatum['rid'],
                            'year' => $fortuneDatum['year'],
                            'scores' => $fortuneDatum['fortune'],
                            'topic' => $fortuneDatum['topic'],
                            'point' => $fortuneDatum['point'],
                            'recode_info' => $backRecode[$fortuneDatum['rid_back']],
                            'version' => $fortuneDatum['version'],
                        ];
                        // 2024年运升级 新数据
                        if (isset($fortuneDatum['extra']) && $fortuneDatum['extra'] !== '')
                        {
                            $extra = json_decode($fortuneDatum['extra'], true);
                            if (isset($extra['important_focus']))
                            {
                                $fortuneInfo['important_focus'] = $extra['important_focus'];
                            }
                            if (isset($extra['important_astro_list']))
                            {
                                $fortuneInfo['important_astro_list'] = $extra['important_astro_list'];
                            }
                        }
                        $fRecode = $fortuneInfo['recode_info'];
                        // 档案唯一标示Key
                        $recodeUniqueKey = "{$fRecode['type']}:{$fRecode['year']}:{$fRecode['month']}:{$fRecode['day']}:{$fRecode['hour']}:{$fRecode['minute']}:{$fRecode['timezone']}:{$fRecode['ew']}:{$fRecode['long_deg']}:{$fRecode['long_min']}:{$fRecode['ns']}:{$fRecode['lat_deg']}:{$fRecode['lat_min']}:{$fRecode['is_summer']}:{$fRecode['live_country']}{$fRecode['live_province']}{$fRecode['live_city']}";
                        $resFortuneData[$fortuneDatum['rid'] . ':' . $fortuneDatum['year']][$recodeUniqueKey] = \GuzzleHttp\json_encode($fortuneInfo, JSON_UNESCAPED_UNICODE);
                    }

                    return $resFortuneData;
                }
                catch (Exception $e)
                {
                    Log::write($e->getMessage() . '[' . $e->getFile() . ':' . $e->getLine() . ']', 'error', true);
                    return [];
                }
            }, $field, 'list_details_v2');

        foreach ($resData as $k => $v)
        {
            foreach ($v as $k1 => $v1)
            {
                $d = json_decode($v1, true);
                $scores = json_decode($d['scores'], true);
                $d['leida'] = $scores['leida'] ?? null;
                $d['toutu'] = $scores['toutu'] ?? -1;
                $d['important_focus'] = $scores['important_focus'] ?? null;
                $d['important_astro_list'] = $scores['important_astro_list'] ?? null;
                unset($scores['leida'], $scores['toutu'], $scores['important_focus'], $scores['important_astro_list']);
                $d['scores'] = json_encode($scores, JSON_UNESCAPED_UNICODE);
                $resData[$k][$k1] = json_encode($d);
            }
        }

        return $resData;
    }

    /**
     * 获取档案 当前年 年运信息（已解锁）
     * @param array $recode 档案信息
     * @param string $year 年
     * @return array
     * @throws Exception
     */
    public function getFortuneYearDetail(array $recode, string $year)
    {
        $data = $this->batchGetRecodeFortuneYearInfo((int)$recode['id'], [$year]);

        if (empty($data))
        {
            return null;
        } else
        {
            $data = current($data);
        }

        $recodeUniqueKey1 = "{$recode['type']}:{$recode['year']}:{$recode['month']}:{$recode['day']}:{$recode['hour']}:{$recode['minute']}:{$recode['timezone']}:{$recode['ew']}:{$recode['long_deg']}:{$recode['long_min']}:{$recode['ns']}:{$recode['lat_deg']}:{$recode['lat_min']}:{$recode['is_summer']}";
        $recodeUniqueKey2 = "{$recodeUniqueKey1}:{$recode['live_country']}{$recode['live_province']}{$recode['live_city']}";

        if (isset($data[$recodeUniqueKey2]))
        {   // 档案未变更
            $fortuneInfo = \GuzzleHttp\json_decode($data[$recodeUniqueKey2], true);
            if ($fortuneInfo['status'] > 0)
            {
                $fortuneInfo['recode_is_change'] = false;

                if ($fortuneInfo['status'] == 2)
                {   // 已解锁 并 计算完成
                    $fortuneInfo['scores'] = \GuzzleHttp\json_decode($fortuneInfo['scores'], true);
                    $fortuneInfo['point'] = \GuzzleHttp\json_decode($fortuneInfo['point'], true);

                    $monthFortuneModel = new MonthFortune();
                    $months = [];
                    for ($i = 1; $i < 13; $i++)
                    {
                        $month = $i < 10 ? '0' . $i : $i;
                        $months[] = $fortuneInfo['year'] . '-' . $month;
                    }

                    $monthFortuneData = $monthFortuneModel->batchGetRecodeFortuneMonthInfo($fortuneInfo['rid'], $months, [$recodeUniqueKey1]);

                    $topics = [];
                    $insertDataMonth = [];
                    $insterMonths = [];
                    foreach ($months as $monthItem)
                    {
                        $cackeKey = $fortuneInfo['rid'] . ':' . $monthItem;
                        if (!empty($monthFortuneData[$cackeKey][$recodeUniqueKey1]))
                        {
                            $monthFortuneInfoItem = \GuzzleHttp\json_decode($monthFortuneData[$cackeKey][$recodeUniqueKey1], true);
                            if ($monthFortuneInfoItem['fortune'])
                            {
                                $topics += \GuzzleHttp\json_decode($monthFortuneInfoItem['fortune'], true);
                            } else
                            {
                                $data = (new FortunesChange())->jobInit($fortuneInfo['recode_info'], $monthItem, 'month');

                                $topics += $data['topics'];

                                $insertDataMonth[] = [
                                    'type' => 0,
                                    'order_id' => 0,
                                    'rid_back' => $fortuneInfo['rid_back'],
                                    'status' => 0,
                                    'rid' => $fortuneInfo['rid'],
                                    'month' => $monthItem,
                                    'fortune' => \GuzzleHttp\json_encode($data['topics']),
                                ];

                                $insterMonths[] = $monthItem;
                            }
                        } else
                        {   // 年度运势-月份数据缺失 临时计算写入
                            $data = (new FortunesChange())->jobInit($fortuneInfo['recode_info'], $monthItem, 'month');

                            $topics += $data['topics'];

                            $insertDataMonth[] = [
                                'type' => 0,
                                'order_id' => 0,
                                'rid_back' => $fortuneInfo['rid_back'],
                                'status' => 0,
                                'rid' => $fortuneInfo['rid'],
                                'month' => $monthItem,
                                'fortune' => \GuzzleHttp\json_encode($data['topics']),
                            ];

                            $insterMonths[] = $monthItem;
                        }
                    }

                    if ($insertDataMonth)
                    {   // 年度运势-月份数据缺失 临时计算写入
                        $map = [
                            'type' => 0, // 0=>年运逻辑生成 1=>订单（order_id为订单编号） 2=>赠送（order_id为赠送id）
                            'rid' => $fortuneInfo['rid'],
                            'rid_back' => $fortuneInfo['rid_back'],
                            'month' => ['in', $insterMonths],
                        ];

                        $monthFortuneModel->addFortuneForYear($insertDataMonth, $map);

                        foreach ($insterMonths as $insterMonthsItem)
                        {   // 删除运势缓存
                            CacheManage::getInstance()->setCacheConfig('fortune.fortune_month')
                                ->setCacheKeyDetail('details_v2', $fortuneInfo['rid'] . ':' . $insterMonthsItem)
                                ->rmCache('details_v2');
                        }
                    }
                    $fortuneInfo['topics'] = $topics;
                }
                $fortuneInfo['version'] = $fortuneInfo['version'] ?? '';
                return $fortuneInfo;
            } else
            {
                unset($data[$recodeUniqueKey2]);
            }
        }

        $resFortune = null;
        foreach ($data as $fortuneStr)
        {
            $fortuneInfo = \GuzzleHttp\json_decode($fortuneStr, true);
            if ($fortuneInfo['status'] > 0)
            {
                if (is_null($resFortune))
                {
                    $resFortune = $fortuneInfo;
                }

                if ($fortuneInfo['id'] > $resFortune['id'])
                {
                    $resFortune = $fortuneInfo;
                }
            }
        }

        if ($resFortune['status'] == 2)
        {   // 已解锁 并 计算完成
            $recode = $resFortune['recode_info'];
            $resFortune['scores'] = \GuzzleHttp\json_decode($resFortune['scores'], true);
            $resFortune['point'] = \GuzzleHttp\json_decode($resFortune['point'], true);

            $recodeUniqueKey1 = "{$recode['type']}:{$recode['year']}:{$recode['month']}:{$recode['day']}:{$recode['hour']}:{$recode['minute']}:{$recode['timezone']}:{$recode['ew']}:{$recode['long_deg']}:{$recode['long_min']}:{$recode['ns']}:{$recode['lat_deg']}:{$recode['lat_min']}:{$recode['is_summer']}";

            $monthFortuneModel = new MonthFortune();
            $months = [];
            for ($i = 1; $i < 13; $i++)
            {
                $month = $i < 10 ? '0' . $i : $i;
                $months[] = $resFortune['year'] . '-' . $month;
            }

            $monthFortuneData = $monthFortuneModel->batchGetRecodeFortuneMonthInfo($resFortune['rid'], $months, [$recodeUniqueKey1]);

            $topics = [];
            $insertDataMonth = [];
            $insterMonths = [];
            foreach ($months as $monthItem)
            {
                $cackeKey = $resFortune['rid'] . ':' . $monthItem;
                if (!empty($monthFortuneData[$cackeKey][$recodeUniqueKey1]))
                {
                    $monthFortuneInfoItem = \GuzzleHttp\json_decode($monthFortuneData[$cackeKey][$recodeUniqueKey1], true);
                    $topics += \GuzzleHttp\json_decode($monthFortuneInfoItem['fortune'], true);
                } else
                {   // 年度运势-月份数据缺失 临时计算写入
                    $data = (new FortunesChange())->jobInit($resFortune['recode_info'], $monthItem, 'month');

                    $topics += $data['topics'];

                    $insertDataMonth[] = [
                        'type' => 0,
                        'order_id' => 0,
                        'rid_back' => $resFortune['rid_back'],
                        'status' => 0,
                        'rid' => $resFortune['rid'],
                        'month' => $monthItem,
                        'fortune' => \GuzzleHttp\json_encode($data['topics']),
                    ];

                    $insterMonths[] = $monthItem;
                }
            }

            if ($insertDataMonth)
            {   // 年度运势-月份数据缺失 临时计算写入
                $map = [
                    'type' => 0, // 0=>年运逻辑生成 1=>订单（order_id为订单编号） 2=>赠送（order_id为赠送id）
                    'rid' => $resFortune['rid'],
                    'rid_back' => $resFortune['rid_back'],
                    'month' => ['in', $insterMonths],
                ];

                $monthFortuneModel->addFortuneForYear($insertDataMonth, $map);

                foreach ($insterMonths as $insterMonthsItem)
                {   // 删除运势缓存
                    CacheManage::getInstance()->setCacheConfig('fortune.fortune_month')
                        ->setCacheKeyDetail('details_v2', $resFortune['rid'] . ':' . $insterMonthsItem)
                        ->rmCache('details_v2');
                }
            }

            $resFortune['topics'] = $topics;
        }
        $resFortune['version'] = $resFortune['version'] ?? '';
        $resFortune['recode_is_change'] = true;

        return $resFortune;
    }
}
